
module tcp_rx #(
    parameter   SOURCE_PORT         = 16'd5001
)(
    input                       i_clk                       ,
    input                       i_rst                       ,
    input                       i_set_source_port_valid     ,
    input   [15: 0]             i_set_source_port           ,
    input                       s_axis_tvalid               ,
    input   [7 : 0]             s_axis_tdata                ,
    input                       s_axis_tlast                ,
    input   [71: 0]             s_axis_tuser                ,
    output                      m_axis_tvalid               ,
    output  [7 : 0]             m_axis_tdata                ,
    output                      m_axis_tlast                ,
    output  [63: 0]             m_axis_tuser                ,
    output                      o_tcp_rx_valid              , 
    output  [31: 0]             o_tcp_rx_id                 ,
    output  [31: 0]             o_tcp_rx_ack_id             ,
    output  [5 : 0]             o_tcp_rx_flags              ,
    output  [15: 0]             o_tcp_rx_windows_size        
);

    localparam  UDP_PKG_TYPE     = 8'd6                     ; 

    logic   [31: 0]             set_source_port             ;
    logic   [15: 0]             tcp_rx_cnt                  ;
    logic   [7 : 0]             tcp_s_axis_tdata            ;
    logic                       tcp_s_axis_tvalid           ;
    logic                       tcp_s_axis_tlast            ;
    logic                       tcp_rx_valid                ;
    logic   [15: 0]             tcp_rx_pkg_len              ;
    logic   [15: 0]             tcp_rx_data_len             ;
    logic   [7 : 0]             tcp_rx_head_len             ;
    logic   [31: 0]             tcp_rx_source_ip            ;
    logic   [15: 0]             tcp_rx_source_port          ;
    logic   [15: 0]             tcp_rx_target_port          ;
    logic   [31: 0]             tcp_rx_id                   ;
    logic   [31: 0]             tcp_rx_ack_id               ;
    logic   [5 : 0]             tcp_rx_flags                ;
    logic   [15: 0]             tcp_rx_windows_size         ;
    logic                       tcp_m_axis_tvalid           ;
    logic   [7 : 0]             tcp_m_axis_tdata            ;
    logic                       tcp_m_axis_tlast            ;
    logic   [31: 0]             tcp_m_axis_tuser            ;   
    

    assign o_tcp_rx_valid           = tcp_rx_valid          ; 
    assign o_tcp_rx_id              = tcp_rx_id             ;
    assign o_tcp_rx_ack_id          = tcp_rx_ack_id         ;
    assign o_tcp_rx_flags           = tcp_rx_flags          ;
    assign o_tcp_rx_windows_size    = tcp_rx_windows_size   ;
    assign m_axis_tvalid        = tcp_m_axis_tvalid     ;
    assign m_axis_tdata         = tcp_m_axis_tdata      ;
    assign m_axis_tlast         = tcp_m_axis_tlast      ;
    assign m_axis_tuser         = tcp_m_axis_tuser      ;


    always_ff @( posedge i_clk ) begin
        if(i_rst)
            set_source_port <= SOURCE_PORT;
        else if(i_set_source_port_valid)
            set_source_port <= i_set_source_port;
        else 
            set_source_port <= set_source_port;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst) begin
            tcp_s_axis_tvalid <= 0;            
            tcp_s_axis_tdata <= 0; 
            tcp_s_axis_tlast <= 0;  
            tcp_rx_pkg_len <= 0; 
            tcp_rx_data_len <= 0; 
            tcp_rx_source_ip <= 0;       
        end
        else if(s_axis_tuser[23:16] == UDP_PKG_TYPE) begin
            tcp_s_axis_tvalid <= s_axis_tvalid;            
            tcp_s_axis_tdata <= s_axis_tdata;
            tcp_s_axis_tlast <= s_axis_tlast;
            tcp_rx_pkg_len <= s_axis_tuser[15:0];
            tcp_rx_data_len <= s_axis_tuser[15:0] - 20;

            tcp_rx_source_ip <= s_axis_tuser[55:24];
        end
        else begin
            tcp_s_axis_tvalid <= 0;            
            tcp_s_axis_tdata <= tcp_s_axis_tdata;
            tcp_s_axis_tlast <= 0;
            tcp_rx_pkg_len <= tcp_rx_pkg_len;
            tcp_rx_data_len <= tcp_rx_data_len;
            tcp_rx_source_ip <= tcp_rx_source_ip;
        end 
    end

    

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_cnt <= 0;
        else if(tcp_s_axis_tvalid)
            tcp_rx_cnt <= tcp_rx_cnt + 1;
        else 
            tcp_rx_cnt <= 0;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_source_port <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 0 && tcp_rx_cnt < 2)
            tcp_rx_source_port <= {tcp_rx_source_port[7:0],tcp_s_axis_tdata};
        else
            tcp_rx_source_port <= tcp_rx_source_port;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_target_port <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 2 && tcp_rx_cnt < 4)
            tcp_rx_target_port <= {tcp_rx_target_port[7:0],tcp_s_axis_tdata};
        else
            tcp_rx_target_port <= tcp_rx_target_port;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_id <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 4 && tcp_rx_cnt < 8)
            tcp_rx_id <= {tcp_rx_id[23:0],tcp_s_axis_tdata};
        else
            tcp_rx_id <= tcp_rx_id;  
    end

    

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_ack_id <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 8 && tcp_rx_cnt < 12)
            tcp_rx_ack_id <= {tcp_rx_ack_id[23:0],tcp_s_axis_tdata};
        else
            tcp_rx_ack_id <= tcp_rx_ack_id;  
    end

    
    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_head_len <= 5;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 12 && tcp_rx_cnt < 13)
            tcp_rx_head_len <= tcp_s_axis_tdata[7:4];
        else 
            tcp_rx_head_len <= tcp_rx_head_len;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_flags <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 13 && tcp_rx_cnt < 14)
            tcp_rx_flags <= tcp_s_axis_tdata[5:0];
        else 
            tcp_rx_flags <= tcp_rx_flags;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_windows_size <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= 14 && tcp_rx_cnt < 16)
            tcp_rx_windows_size <= {tcp_rx_windows_size[7:0],tcp_s_axis_tdata};
        else 
            tcp_rx_windows_size <= tcp_rx_windows_size;  
    end

    

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_m_axis_tvalid <= 0;
        else if(tcp_s_axis_tvalid && tcp_rx_cnt >= (tcp_rx_head_len<<4) && tcp_rx_target_port == set_source_port)
            tcp_m_axis_tvalid <= tcp_s_axis_tvalid;
        else 
            tcp_m_axis_tvalid <= 0;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_m_axis_tdata <= 0;
        else 
            tcp_m_axis_tdata <= tcp_s_axis_tdata;  
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_m_axis_tlast <= 0;
        else if(tcp_m_axis_tvalid && tcp_rx_target_port == set_source_port)
            tcp_m_axis_tlast <= tcp_s_axis_tlast;
        else  
            tcp_m_axis_tlast <= 0;
    end

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_rx_valid <= 0;
        else if(tcp_rx_target_port == set_source_port)
            tcp_rx_valid <= tcp_s_axis_tlast;
        else  
            tcp_rx_valid <= 0;
    end

    

    always_ff @( posedge i_clk ) begin
        if(i_rst)
            tcp_m_axis_tuser <= 0;
        else 
            tcp_m_axis_tuser <= {tcp_rx_source_port,tcp_rx_source_ip,tcp_rx_data_len};  
    end






endmodule